/**
 * @description 深度映射对象的键
 * @param {*} obj 
 * @param {*} fn 
 * @returns 
 */
const deepMapKeys = (obj, fn) =>
  // 判断 key 的数据类型（数组/对象/基础数据类型）
  Array.isArray(obj)
    // 使用 Array.map() 递归数组的 key。
    ? obj.map(val => deepMapKeys(val, fn))
    : typeof obj === 'object'
    // 使用 Object.keys(obj) 遍历对象的 key。
    // 使用 Array.prototype.reduce() 创建一个新的对象具有相同的 value 和 key 并使用fn。
    ? Object.keys(obj).reduce((acc, current) => {
        const key = fn(current);
        const val = obj[current];
        // 判断是否为对象需递归
        acc[key] =
          val !== null && typeof val === 'object' ? deepMapKeys(val, fn) : val;
        return acc;
      }, {})
    : obj;
// 例子
const obj = {
  foo: '1',
  nested: {
    child: {
      withArray: [
        {
          grandChild: ['hello']
        }
      ]
    }
  }
};
const upperKeysObj = deepMapKeys(obj, key => key.toUpperCase());
/*
{
  "FOO":"1",
  "NESTED":{
    "CHILD":{
      "WITHARRAY":[
        {
          "GRANDCHILD":[ 'hello' ]
        }
      ]
    }
  }
}
*/